/**
 * Table行列锁定
 *
 * @author sunfengming <sunfengming@ec3s.com>
 */
(function(){
    var LockTable = this.LockTable = new Class({
        tableDom : null,
        parentDom : null,
        tableWidth : 0,
        oldTableWidth : 0,
        tableHeight : 0,
        tableMinHeight : 550,
        lockColumn :  null,
        tableCellSize : [],
        lockColumnWidth : 0,
        dataColumnWidth : 0,
        cellPadding : 0,
        scrollWidth : 0,
        rowCellCount : 0,
        initialize : function(table){
            var _this = this;
            if (1 > table.length) {
                //若没有表格
                return false;
            }
            //获取原始表
            var oTable = table.pop();
            if ('table' != (oTable.nodeName).toLowerCase() || 0 === oTable.getElements('td').length) {
                //若参数不是表格,或表格无数据
                return false;
            }
            var oTableCell = oTable.getElements('td')[0];
            var lockTh = oTable.getElements('.lock-th')[0];
            var cellPaddingWidth = 0;
            var cellPaddingHeight = 0;
            try {
                cellPaddingWidth = this.cellPadding = oTableCell.getStyle('padding-left').toInt() + oTableCell.getStyle('padding-right').toInt();
                cellPaddingHeight = oTableCell.getStyle('padding-top').toInt() + oTableCell.getStyle('padding-bottom').toInt();
            } catch (e) {
                cellPaddingWidth = 0;
                cellPaddingHeight = 0;
            }

            this.scrollWidth = this.getScrollWidth();
            var oTableTrs = oTable.getElements('tr');
            //滚动条占位行
            var scrollRow = new Element('tr');
            var scrollRowCell = new Element('td');
            scrollRow.addClass('scroll-row');
            scrollRowCell.setStyle('height', this.scrollWidth - cellPaddingHeight + 'px');
            lockTh.getChildren().forEach(function(thCell){
                scrollRow.grab(scrollRowCell.clone());
            });
            //滚动条占位列
            var scrollTh = new Element('th'),
            scrollCell = new Element('td'),
            scrollThDiv = new Element('div');
            scrollTh.setStyles({
                'width':this.scrollWidth - cellPaddingWidth + 'px',
                'border' : '0px none'
            });
            scrollCell.setStyles({
                'width':this.scrollWidth - cellPaddingWidth + 'px',
                'border' : '0px none'
            });
            scrollCell.setProperty('rowspan', oTableTrs.length);
            scrollThDiv.setStyles({
                'width': this.scrollWidth - cellPaddingWidth + 'px',
                'overflow':'hidden',
                'margin' : '0px',
                'padding' : '0px'
            });
            scrollTh.grab(scrollThDiv.clone());
            //表头滚动条占位
            lockTh.grab(scrollTh);
            this.parentDom = oTable.getParent();
            var parentDomPaddingWidth = this.parentDom.getStyle('padding-left').toInt() + this.parentDom.getStyle('padding-right').toInt();
            var parentDomWidth =  this.parentDom.getSize().x - parentDomPaddingWidth;
            //空的表格外壳
            this.tableDom = (oTable.clone()).empty();
            //表格最小宽度为占满页面
            this.tableWidth = (oTable.getSize().x < parentDomWidth) ? parentDomWidth : oTable.getSize().x ;
            this.tableHeight = (oTable.getSize().y > this.tableMinHeight) ? this.tableMinHeight : oTable.getSize().y + this.scrollWidth;

            //复制表外壳
            var orignTable = this.tableDom.clone();

            //去除标准浏览器为table增加的tbody节点，生成表 orignTable

            oTableTrs.forEach(function(row, i){
                var rowChildren = row.getChildren();
                if (row.hasClass('lock-th')) {
                    var nextRow = this.firstDataRow = row.getNext();
                    this.rowCellCount = rowChildren.length;
                    for ( var cells = 0, cellCount = rowChildren.length; cells < cellCount; cells++) {
                        var cell = rowChildren[cells];
                        //cell padding left + right width
                        var cellWidth = cell.getSize().x - this.cellPadding;
                        this.tableCellSize[cells] = cellWidth;
                        cell.setStyles({
                            width : cellWidth + 'px'
                        });
                        try {
                            var nextRowChildren = nextRow.getChildren();
                            nextRowChildren[cells].setStyle('width', cellWidth + 'px');
                        } catch (e) {
                            // 该行不存在的话就不处理了，直接进入下一步
                            scrollRow.dispose();
                        }
                    }
                }
                try {
                    nextRow.grab(scrollCell.clone());
                } catch (e) {
                    // 该行不存在的话就不处理了，直接进入下一步
                }
                orignTable.grab(row.clone());
            }, this);
            //删除原始表
            oTable.dispose();
            orignTable.grab(scrollRow);
            var resultTabel = this.getLockCell(orignTable);
            this.dataColumn = resultTabel[1];
            this.lockColumn = resultTabel[0];
        },
        getPreLockRow : function(table){
            //锁定属性决定行
            var lockDecideRow = ($(table).getElements('.lock-th')).pop();
            //决定行前面的兄弟元素是不是行
            var previouslockDecideRow = lockDecideRow.getPrevious();
            if (null == previouslockDecideRow || 'tr' != (previouslockDecideRow.nodeName).toLowerCase()) {
                previouslockDecideRow = null;
            }
            return previouslockDecideRow;
        },
        setPreLockRowCell : function(preLockRow){
            var cellArray = [];
            
            preLockRow && preLockRow.getChildren().forEach(function(cell){
                if(cell.getProperty('colspan')){
                    for(var i = 1,colspan = cell.getProperty('colspan'); i<=colspan; i++){
                        Array.push(cellArray, cell);
                    }
                }else{
                    Array.push(cellArray, cell);
                }
            });
            this.cellArray = cellArray;
        },
        getPreLockRowCell : function(cellNum){
            return this.cellArray[cellNum];
        },
        getLockCell : function(orignTable){
            //锁定属性决定行
            var lockDecideRow = ($(orignTable).getElements('.lock-th')).pop();
            var lockCellArray = [];
            for ( var i = 0, countCells = lockDecideRow.getChildren().length; i < countCells; i++) {
                var subCells = (lockDecideRow.getChildren())[i];
                //若此子列的lock属性为true,将此列号放入lockCellArray
                if (subCells.getProperty('lock')) {
                    Array.push(lockCellArray, i);
                }
            }
            //去除重复的待锁定列
            Array.unique(lockCellArray)
            return this.createLockColumn(lockCellArray, orignTable.clone());
        },
        mergePreLockRowCell : function(preLockRowCellArray){
            //统计次数，多列相同的合并
            var preLockRowCells = [];
            if(!preLockRowCellArray){
                preLockRowCellArray=[];
            }
            for(var i = 0;i<preLockRowCellArray.length;)
            {
                var count = 0;
                for(var j=i;j<preLockRowCellArray.length;j++){
                    if(preLockRowCellArray[i] == preLockRowCellArray[j]){
                        count++;
                        if(j == preLockRowCellArray.length -1 && arguments[1]){
                            count++;
                        }
                    }
                }

                preLockRowCellArray[i].setProperty('colspan', count);
                Array.push(preLockRowCells, preLockRowCellArray[i]);
                i+=count;
            }

            return preLockRowCells;
        },
        createLockColumn : function(lockcells, table){
            var _this = this;
            var previouslockDecideRow = this.getPreLockRow(table);
            this.setPreLockRowCell(previouslockDecideRow);

            var tmpColumn = this.tableDom.clone();

            /**
             * 决定行前面的兄弟元素
             */
            if(previouslockDecideRow) {
                previouslockDecideRow.dispose();
                var previouslockDecideRowDom = previouslockDecideRow.clone().empty();
                var overPreviouslockDecideRowDom = previouslockDecideRowDom.clone();
                var preLockRowCellArray = [];
                lockcells.forEach(function(cellNum){
                    Array.push(preLockRowCellArray, _this.getPreLockRowCell(cellNum));
                });

                var overPreLockRowCellArray = $A(this.cellArray);
                preLockRowCellArray.forEach(function(i){
                    for ( var j = 0; j < overPreLockRowCellArray.length; j++) {
                        if(overPreLockRowCellArray[j] == i){
                            overPreLockRowCellArray.splice(j,1);
                            break;
                        }
                    }
                });
                var preLockRowCells = this.mergePreLockRowCell(preLockRowCellArray);
                
                previouslockDecideRowDom.adopt(preLockRowCells);
                tmpColumn.grab(previouslockDecideRowDom.clone());

            }

            table.getElements('tr').forEach(function(row, r){
                var tmpEmptyRow = row.clone().empty();
                var rowChildren = row.getChildren();
                for ( var i = 0; i < lockcells.length; i++) {
                    var lockcell = lockcells[i] ;
                    if (0 == r) {
                        _this.lockColumnWidth += _this.tableCellSize[lockcell] + _this.cellPadding;
                    }
                    tmpEmptyRow.adopt(rowChildren[lockcell]);
                }
                tmpColumn.adopt(tmpEmptyRow);
            });
            this.dataColumnWidth = this.tableWidth - this.lockColumnWidth;
            if(previouslockDecideRow){
                var overPreLockRowCells = this.mergePreLockRowCell(overPreLockRowCellArray, true);
                overPreviouslockDecideRowDom.adopt(overPreLockRowCells);
                table.grab(overPreviouslockDecideRowDom, 'top');
            }
            return [tmpColumn, table];
        },
        toDiv : function(column){
            var tableDom = column.clone().empty();
            var tbody = new Element('tbody');
            var headTbody = tbody.clone();
            var bodyTbody = tbody.clone();
            var tableHead = tableDom.clone();
            var tableBody = tableDom.clone();
            tableHead.grab(headTbody);
            var lockTh = column.getElement('.lock-th');
            var preLockTh = this.getPreLockRow(column);
            if(preLockTh){
                headTbody.adopt(preLockTh);
            }
            headTbody.adopt(lockTh);
            var columnChildren = column.getChildren();
            tableBody.grab(bodyTbody);
            columnChildren.inject(bodyTbody);
            
            var tableDiv = new Element('div');
            var headDiv = new Element('div');
            var bodyDiv = new Element('div');
            headDiv.grab(tableHead);
            bodyDiv.grab(tableBody);
            tableDiv.grab(headDiv);
            tableDiv.grab(bodyDiv);
            return tableDiv;
        },
        getScrollWidth : function () {
            var noScroll, scroll, oDiv = document.createElement("DIV");
            oDiv.style.cssText = "position:absolute; top:-1000px; width:100px; height:100px; overflow:hidden;";
            noScroll = document.body.appendChild(oDiv).clientWidth;
            oDiv.style.overflowY = "scroll";
            scroll = oDiv.clientWidth;
            document.body.removeChild(oDiv);
            return noScroll-scroll;
        },
        renderScroll : function(size, target, lockTarget){
            var vScroll = new Element('div');
            var vScrollDom = new Element('div');
            var hScroll = new Element('div');
            var targetSize = target.getSize();
            var headSize = target.getChildren()[0].getSize();
            var targetCoo = target.getCoordinates();
            var scrollWidth = this.scrollWidth;
            var vScrollThin = new Element('div');
            var hScrollThin = new Element('div');
            var targetHead = target.getChildren()[0];
            var targetBody = target.getChildren()[1];
            var lockTargetHead = lockTarget.getChildren()[0];
            var lockTargetBody = lockTarget.getChildren()[1];
            var lockTargetSize = lockTarget.getSize();
            var lockHeadSize = lockTargetHead.getSize();
            var dataColumnFirstCell = targetBody.getElement('table').getElements('tr')[0].getChildren('td')[0];
            var dataColumnFirstTh = targetHead.getElement('table').getElement('.lock-th').getChildren('th')[0];
            var scrollWheel = 20;
            target.setStyle('position', 'relative');
            targetHead.setStyles({
                height : headSize.y + 'px',
                width : targetSize.x + 'px',
                overflow : 'hidden'
            });

            targetBody.setStyles({
                height : targetSize.y - headSize.y + 'px',
                width : targetSize.x + 'px',
                overflow : 'hidden'
            });

            lockTargetHead.setStyles({
                height : lockHeadSize.y + 'px',
                width : lockTargetSize.x + 'px',
                overflow : 'hidden'
            });

            lockTargetBody.setStyles({
                height : lockTargetSize.y - lockHeadSize.y + 'px',
                width : lockTargetSize.x + 'px',
                overflow : 'hidden'
            });
            vScrollThin.setStyles({
                width : '1px',
                height : size.y + 'px',
                'font-size' : '0px'
            });

            hScrollThin.setStyles({
                height : '1px',
                width : (targetSize.x - scrollWidth) * size.x / targetSize.x + 'px',
                'font-size' : '0px'
            });
            vScroll.setStyles({
                width : scrollWidth + 'px',
                height : targetSize.y - headSize.y + 'px',
                'overflow-x' : 'hidden',
                'overflow-y' : 'scroll'
            });
            hScroll.setStyles({
                height : scrollWidth + 'px',
                width : targetSize.x - scrollWidth + 'px',
                'overflow-x' : 'auto',
                'overflow-y' : 'hidden',
                position : 'absolute',
                bottom : 0
            });
            vScrollDom.setStyles({
                position : 'absolute',
                top : headSize.y + 'px',
                right : 0,
                bottom : 0 + 'px',
                background:'#FFF'
            });

            hScroll.grab(hScrollThin);
            vScroll.grab(vScrollThin);
            vScrollDom.grab(vScroll);
            target.grab(hScroll);
            target.grab(vScrollDom);

            window.addEvent('resize', function(){
                targetHead.setStyle('width', target.getSize().x);
                targetBody.setStyle('width', target.getSize().x);
                hScroll.setStyles({
                    width : target.getSize().x - scrollWidth + 'px'
                });
                if (size.x <= target.getSize().x) {
                    targetHead.getElement('table').setStyle('width', target.getSize().x + 'px');
                    targetBody.getElement('table').setStyle('width', target.getSize().x + 'px');

                    var dataFirstWidth = target.getSize().x - size.x;
                    dataColumnFirstTh.setStyle('width', dataFirstWidth + 'px');
                    dataColumnFirstCell.setStyle('width', dataFirstWidth + 'px');

                    hScrollThin.setStyles({
                        width : (target.getSize().x - scrollWidth) * target.getSize().x / target.getSize().x + 'px'
                    });
                }
            });
            hScroll.addEvent('scroll', function(){
                /**
                 * 滚动差比
                 */
                var o = targetSize.x / (targetSize.x - scrollWidth);
                var oldScroll = target.getChildren()[1].getScroll();
                var scroll = hScroll.getScroll();
                target.getChildren()[0].scrollTo(scroll.x * o, 0);
                target.getChildren()[1].scrollTo(scroll.x * o, oldScroll.y);
            });

            vScroll.addEvent('scroll', function(){
                var oldScroll = target.getChildren()[1].getScroll();
                var scroll = vScroll.getScroll();
                target.getChildren()[1].scrollTo(oldScroll.x, scroll.y);
                lockTarget.getChildren()[1].scrollTo(oldScroll.x, scroll.y);
            });

            target.addEvent('mousewheel', function(e) {
                var oldScroll = vScroll.getScroll().y;
                if (e.wheel > 0) {
                    if (0 < vScroll.getScroll().y) {
                        e.stop();
                    }
                    vScroll.scrollTo(0, oldScroll - (scrollWheel * e.wheel));
                } else {
                    if (vScroll.getScroll().y < vScroll.getScrollSize().y - vScroll.getSize().y) {
                        e.stop();
                    }
                    vScroll.scrollTo(0, oldScroll - (scrollWheel * e.wheel));
                }
            });

            lockTarget.addEvent('mousewheel', function(e) {
                var oldScroll = vScroll.getScroll().y;
                if (e.wheel > 0) {
                    if (0 < vScroll.getScroll().y) {
                        e.preventDefault();
                    }
                    vScroll.scrollTo(0, oldScroll - (scrollWheel * e.wheel));
                } else {
                    if (vScroll.getScroll().y < vScroll.getScrollSize().y - vScroll.getSize().y) {
                        e.preventDefault();
                    }
                    vScroll.scrollTo(0, oldScroll - (scrollWheel * e.wheel));
                }
            });
            vScroll.scrollTo(0, 0);
        },
        render : function(){
            if ('undefined' === typeof this.dataColumn) {
                return false;
            }
            var tableDiv = new Element('div');
            var marginDiv = new Element('div');
            var lockTableDiv = this.toDiv(this.lockColumn);
            lockTableDiv.setStyles({
                width:this.lockColumnWidth,
                height: this.tableHeight + 'px',
                overflow:'hidden',
                'float': 'left',
                'border-right':'1px solid #aaa'
            });

            var lockTableWidth = this.lockColumnWidth + 1;
            if(lockTableDiv.getElements('td').length <= 0){
                lockTableWidth = 0;
                lockTableDiv.setStyle('display', 'none');
            }
            this.dataColumn.setStyles({
                width: this.dataColumnWidth
            });
            var dataTableDiv = this.toDiv(this.dataColumn);
            dataTableDiv.setStyles({
                height: this.tableHeight + 'px',
                overflow:'hidden',
                'margin-left' : lockTableWidth + 'px'
            });
            marginDiv.setStyles({
                'float' : 'right',
                'margin-left' : - lockTableWidth + 'px',
                width : '100%',
                height : this.tableHeight + 'px'
            });

            marginDiv.grab(dataTableDiv);
            tableDiv.grab(marginDiv);
            tableDiv.grab(lockTableDiv);
            tableDiv.setStyles({
                'height' : this.tableHeight + 'px'
            })

            this.parentDom.grab(tableDiv);
            this.renderScroll(dataTableDiv.getElements('table')[1].getSize(), dataTableDiv, lockTableDiv);
        }
    });
})();